﻿#ifndef __LUA_FUNCTION_H__
#define __LUA_FUNCTION_H__

#include "./def.h"
#include "./luaconvertor.h"
#include "./userconvertor.h"

#define CONVERT_ARG_FIRST\
    TypeConvertor<P1> convertor1;\
	convertor1.SetLuaState(luaState);\
    convertor1.Init(&paramIndex);\
    P1 p1 = convertor1.GetValue();
#define CONVERT_ARG(n)\
    TypeConvertor<P##n> convertor##n;\
	convertor##n.SetLuaState(luaState);\
    convertor##n.Init(&paramIndex);\
    P##n p##n = convertor##n.GetValue();
#define CONVERT_ARGS(n) APPEND(REPEAT_, n)(CONVERT_ARG, n)

#define REG_FUNCTION(n, c, k)\
    template <class F COMMA_TYPE_PARAMS(n)>\
    static void RegFunc(lua_State* luaState, F(*func)(PARAMS(n)))\
    {\
        lua_pushlightuserdata(luaState, (void*)func);\
        lua_pushcclosure(luaState, StaticEntry<F COMMA_PARAMS(n)>, 1);\
    }\
    template <class T, class F COMMA_TYPE_PARAMS(n)>\
    static void RegFunc(lua_State* luaState, F(T::*func)(PARAMS(n))##c)\
    {\
        static FuncPointerMgr funcptMgr;\
        lua_pushlightuserdata(luaState, funcptMgr.NewPointer(&func, sizeof(func)));\
        lua_pushcclosure(luaState, MemberEntry<T, F COMMA_PARAMS(n)>, 1);\
    }

#define BIND_FUNCTION(n, f, cf)\
    template <class F COMMA_TYPE_PARAMS(n)>\
    static void BindFunc(lua_State* luaState, F(*func)(PARAMS(n)))\
    {\
        f##<F>::RegFunc(luaState, func);\
    }\
    template <class T, class F COMMA_TYPE_PARAMS(n)>\
    static void BindFunc(lua_State* luaState, F(T::*func)(PARAMS(n)))\
    {\
        f##<F>::RegFunc(luaState, func);\
    }\
    template <class T, class F COMMA_TYPE_PARAMS(n)>\
    static void BindFunc(lua_State* luaState, F(T::*func)(PARAMS(n)) const)\
    {\
        cf##<F>::RegFunc(luaState, func);\
    }

#define ENTRY_FUNCTION(n, v, c)\
    template <class F COMMA_TYPE_PARAMS(n)>\
    static int StaticEntry(lua_State* luaState)\
    {\
        F(*func)(PARAMS(n)) = (F(*)(PARAMS(n)))lua_touserdata(luaState, lua_upvalueindex(1));\
        int paramIndex = 1;\
        CONVERT_ARGS(n)\
        v(func(VARS(n)))\
    }\
    template <class T, class F COMMA_TYPE_PARAMS(n)>\
    static int MemberEntry(lua_State* luaState)\
    {\
        typedef F(T::*funckind)(PARAMS(n))##c;\
        funckind* func = (funckind*)lua_touserdata(luaState, lua_upvalueindex(1));\
        T* t = NULL;\
        t = getvalue<T*>(luaState, 1);\
        int paramIndex = 2;\
        CONVERT_ARGS(n)\
        v((t->*(*func))(VARS(n)))\
    }

#define ENTRY_GET_FUNCTION(n, c)\
    template <class F, typename P1>\
    static int StaticEntry(lua_State* luaState)\
    {\
        F(*func)(P1) = (F(*)(P1))lua_touserdata(luaState, lua_upvalueindex(1));\
        TypeConvertor<P1> convertor;\
		convertor.SetLuaState(luaState);\
        P1 p1 = convertor.InitValue();\
        func(p1);\
        return convertor.SetValue(p1);\
    }\
    template <class T, class F, typename P1>\
    static int MemberEntry(lua_State* luaState)\
    {\
        typedef void(T::*funckind)(P1)##c;\
        funckind* func = (funckind*)lua_touserdata(luaState, lua_upvalueindex(1));\
        T* t = NULL;\
        t = getvalue<T*>(luaState, 1);\
        TypeConvertor<P1> convertor;\
		convertor.SetLuaState(luaState);\
        P1 p1 = convertor.InitValue();\
        ((t)->*(*func))(p1);\
        return convertor.SetValue(p1);\
    }

#define ENTRY_WRAPPER_FUNCTION(n, v, c)\
    template <class F, typename T COMMA_TYPE_PARAMS(n)>\
    static int StaticEntry(lua_State* luaState)\
    {\
        F(*func)(T COMMA_PARAMS(n)) = (F(*)(T COMMA_PARAMS(n)))lua_touserdata(luaState, lua_upvalueindex(1));\
        T t = NULL;\
        t = getvalue<T>(luaState, 1);\
        int paramIndex = 2;\
        CONVERT_ARGS(n)\
        v(func(t COMMA_VARS(n)))\
    }\
    template <class T, class F COMMA_TYPE_PARAMS(n)>\
    static int MemberEntry(lua_State* luaState)\
    {\
        return 0;\
    }

#define LUA_RETURN(v)\
    TypeConvertor<F> retConvertor;\
	retConvertor.SetLuaState(luaState);\
    int ret = retConvertor.SetValue(v);\
    return ret;

#define LUA_NORETURN(v)\
    v;\
    return 0;

class FuncPointerMgr;

template <class F>
class LuaFunction
{
public:
    FUNCTION_REPEAT30(REG_FUNCTION, , )
    FUNCTION_REPEAT30(ENTRY_FUNCTION, LUA_RETURN,)
    FUNCTION_REPEAT30(BIND_FUNCTION, LuaFunction, LuaConstFunction)
};

template <>
class LuaFunction <void>
{
public:
    FUNCTION_REPEAT30(REG_FUNCTION, , )
    FUNCTION_REPEAT30(ENTRY_FUNCTION, LUA_NORETURN,)
};

template <class F>
class LuaConstFunction
{
public:
    FUNCTION_REPEAT30(REG_FUNCTION, const, )
    FUNCTION_REPEAT30(ENTRY_FUNCTION, LUA_RETURN, const)
};

template <>
class LuaConstFunction <void>
{
public:
    FUNCTION_REPEAT30(REG_FUNCTION, const, )
    FUNCTION_REPEAT30(ENTRY_FUNCTION, LUA_NORETURN, const)
};

template <class F>
class LuaGetFunction
{
public:
    ENTRY_GET_FUNCTION(1, )
    REG_FUNCTION(1, , )
    BIND_FUNCTION(1, LuaGetFunction, LuaConstGetFunction)
};

template <class F>
class LuaConstGetFunction
{
public:
    ENTRY_GET_FUNCTION(1, const)
    REG_FUNCTION(1, const, )
};

template <class F>
class LuaWrapperFunction
{
public:
    FUNCTION_REPEAT30(REG_FUNCTION, , )
    FUNCTION_REPEAT30(ENTRY_WRAPPER_FUNCTION, LUA_RETURN,)
    FUNCTION_REPEAT30(BIND_FUNCTION, LuaWrapperFunction, )
};

template <>
class LuaWrapperFunction <void>
{
public:
    FUNCTION_REPEAT30(REG_FUNCTION, , )
    FUNCTION_REPEAT30(ENTRY_WRAPPER_FUNCTION, LUA_NORETURN,)
};

//manager tmp pointer in MemberEntry
class FuncPointerMgr
{
    typedef std::vector<void*> PointerList;
    typedef std::vector<void*>::iterator PointerListIterator;
public:
    FuncPointerMgr();
    ~FuncPointerMgr();
public:
    void* NewPointer(void* pt, int len);
private:
    PointerList m_ptList;
};

#endif